package com.archive.forum.service;

import com.archive.forum.dto.CommentDTO;
import com.archive.forum.dto.PaginationDTO;
import com.archive.forum.enums.CommentTypeEnum;
import com.archive.forum.enums.NotificationStatusEnum;
import com.archive.forum.enums.NotificationTypeEnum;
import com.archive.forum.exception.CustomizeException;
import com.archive.forum.exception.ExceptionEnum;
import com.archive.forum.mapper.*;
import com.archive.forum.model.*;
import org.apache.ibatis.session.RowBounds;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class CommentService {
    @Autowired
    private CommentMapper commentMapper;
    @Autowired
    private PostMapper postMapper;
    @Autowired
    private PostExtMapper postExtMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private CommentExtMapper commentExtMapper;
    @Autowired
    private NotificationMapper notificationMapper;
    @Autowired
    private UserLikeMapper userLikeMapper;
    //发帖或回帖
    @Transactional
    public void insert(CommentWithBLOBs comment, User commentator) {
        if(comment.getParentId() == null || comment.getParentId() == 0) {
            throw new CustomizeException(ExceptionEnum.TARGET_PARAM_NOT_FOUND);
        }
        if(comment.getType() == null || CommentTypeEnum.isExist(comment.getType())) {
            throw new CustomizeException(ExceptionEnum.TYPE_PARAM_ERROR);
        }
        if (comment.getType().equals(CommentTypeEnum.COMMENT.getType())) {
            //回复评论
            Comment dbComment = commentMapper.selectByPrimaryKey(comment.getParentId());
            if (dbComment == null) {
                throw new CustomizeException(ExceptionEnum.COMMENT_NOT_FOUND);
            }
            Post post = postMapper.selectByPrimaryKey(dbComment.getParentId());
            commentMapper.insert(comment);
            //增加回复和评论数
            dbComment.setCommentCount(1);
            post.setCommentCount(1);
            postExtMapper.incCommentCount(post);
            commentExtMapper.incCommentCount(dbComment);

            // 创建通知 - 只有当回复的不是自己时才创建
            if (!commentator.getId().equals(post.getCreator())) {
                createNotify(dbComment, post.getCreator(), commentator.getName(),
                        post.getTitle(), NotificationTypeEnum.REPLY_POST, post.getId());
            }

            if (!commentator.getId().equals(dbComment.getCommentator())) {
                createNotify(comment, dbComment.getCommentator(), commentator.getName(),
                        post.getTitle(), NotificationTypeEnum.REPLY_COMMENT, post.getId());
            }
        }else {
            //回复帖子
            Post post = postMapper.selectByPrimaryKey(comment.getParentId());
            if(post==null){
                throw new CustomizeException(ExceptionEnum.POST_NOT_FOUND);
            }
            //增加评论数
            post.setCommentCount(1);
            commentMapper.insert(comment);
            postExtMapper.incCommentCount(post);
            // 创建通知 - 只有当回复的不是自己时才创建
            if (!commentator.getId().equals(post.getCreator())) {
                createNotify(comment, post.getCreator(), commentator.getName(),
                        post.getTitle(), NotificationTypeEnum.REPLY_POST, post.getId());
            }
        }
    }
    //创建通知
    private void createNotify(Comment comment, Integer receiver, String notifierName, String outerTitle, NotificationTypeEnum type, Integer outerId) {
        Notification notification = new Notification();
        notification.setReceiver(receiver);
        notification.setOuterId(outerId);
        notification.setType(type.getType());
        notification.setNotifier(comment.getCommentator());
        notification.setStatus(NotificationStatusEnum.UNREAD.getStatus());
        notification.setGmtCreate(System.currentTimeMillis());
        notification.setNotifierName(notifierName);
        notification.setOuterTitle(outerTitle);
        notificationMapper.insert(notification);
    }
    public List<CommentDTO> listByTargetId(Integer id, CommentTypeEnum type, Integer currentUserId) {
        // 1. 查询评论列表
        CommentExample commentExample = new CommentExample();
        commentExample.createCriteria()
                .andParentIdEqualTo(id)
                .andTypeEqualTo(type.getType());
        commentExample.setOrderByClause("gmt_create desc");
        List<CommentWithBLOBs> comments = commentMapper.selectByExampleWithBLOBs(commentExample);

        if (comments.isEmpty()) {
            return new ArrayList<>();
        }

        // 2. 获取去重的评论人ID
        Set<Integer> commentators = comments.stream()
                .map(Comment::getCommentator)
                .collect(Collectors.toSet());

        // 3. 批量查询用户信息
        UserExample userExample = new UserExample();
        userExample.createCriteria().andIdIn(new ArrayList<>(commentators));
        List<User> users = userMapper.selectByExample(userExample);
        Map<Integer, User> userMap = users.stream()
                .collect(Collectors.toMap(User::getId, user -> user));

        // 4. 如果当前用户已登录，查询点赞状态
        Map<Integer, Boolean> likeStatusMap;
        if (currentUserId != null) {
            // 获取当前评论ID列表
            List<Integer> commentIds = comments.stream()
                    .map(Comment::getId)
                    .collect(Collectors.toList());

            // 批量查询点赞状态
            UserLikeExample likeExample = new UserLikeExample();
            likeExample.createCriteria()
                    .andUserIdEqualTo(currentUserId)
                    .andTargetIdIn(commentIds)
                    .andTypeEqualTo(2); // 2表示评论

            List<UserLike> userLikes = userLikeMapper.selectByExample(likeExample);
            likeStatusMap = userLikes.stream()
                    .collect(Collectors.toMap(
                            UserLike::getTargetId,
                            like -> true
                    ));
        } else {
            likeStatusMap = new HashMap<>();
        }

        // 5. 转换为CommentDTO并设置相关属性
        List<CommentDTO> commentDTOS = comments.stream().map(comment -> {
            CommentDTO commentDTO = new CommentDTO();
            BeanUtils.copyProperties(comment, commentDTO);

            // 设置用户信息
            commentDTO.setUser(userMap.get(comment.getCommentator()));

            // 设置是否为当前用户所有
            commentDTO.setIsOwner(currentUserId != null && currentUserId.equals(comment.getCommentator()));

            // 设置点赞状态
            commentDTO.setIsLiked(likeStatusMap.containsKey(comment.getId()));

            return commentDTO;
        }).collect(Collectors.toList());

        return commentDTOS;
    }

    public CommentWithBLOBs getById(Integer id) {
        return commentMapper.selectByPrimaryKey(id);
    }
    @Transactional
    public void deleteComment(Integer id) {
        Comment comment = commentMapper.selectByPrimaryKey(id);
        if (comment == null) {
            throw new CustomizeException(ExceptionEnum.COMMENT_NOT_FOUND);
        }
        try {
            if (Objects.equals(comment.getType(), CommentTypeEnum.POST.getType())){
                //先记载二级评论数量，再删除所属二级评论，及一级评论
                CommentExample commentExample = new CommentExample();
                commentExample.createCriteria().andParentIdEqualTo(id).andTypeEqualTo(CommentTypeEnum.COMMENT.getType());
                Long totalDeleted =  commentMapper.countByExample(commentExample);
                commentMapper.deleteByExample(commentExample);
                //减少评论数
                Post post = postMapper.selectByPrimaryKey(comment.getParentId());
                post.setCommentCount((int) -(totalDeleted)-1);
                postExtMapper.incCommentCount(post);
                commentMapper.deleteByPrimaryKey(id);
            }else if(Objects.equals(comment.getType(), CommentTypeEnum.COMMENT.getType())){
                //删除二级评论
                Comment dbComment = commentMapper.selectByPrimaryKey(comment.getParentId());
                dbComment.setCommentCount(-1);
                Post post = postMapper.selectByPrimaryKey(dbComment.getParentId());
                post.setCommentCount(-1);
                commentMapper.deleteByPrimaryKey(id);
                postExtMapper.incCommentCount(post);
                commentExtMapper.incCommentCount(dbComment);
            }
        }catch (Exception e) {
            throw new CustomizeException(ExceptionEnum.DELETE_ERROR);
        }
    }
    public void update(CommentWithBLOBs comment) {
        commentMapper.updateByPrimaryKeyWithBLOBs(comment);
    }

    public PaginationDTO list(Integer userId, Integer page, Integer size) {
        PaginationDTO<CommentDTO> paginationDTO = new PaginationDTO<>();

        // 1. 计算总数
        CommentExample countExample = new CommentExample();
        countExample.createCriteria().andCommentatorEqualTo(userId);
        Integer totalCount = (int) commentMapper.countByExample(countExample);

        // 2. 计算总页数
        Integer totalPage = (totalCount + size - 1) / size; // 向上取整

        // 3. 处理页码越界
        if (totalPage > 0) {
            page = Math.max(1, Math.min(page, totalPage));
        } else {
            page = 1;
            totalPage = 1;
        }

        // 4. 执行查询
        Integer offset = size * (page - 1);
        CommentExample queryExample = new CommentExample();
        queryExample.createCriteria().andCommentatorEqualTo(userId);
        queryExample.setOrderByClause("gmt_create desc");

        List<CommentWithBLOBs> comments = commentMapper.selectByExampleWithBLOBsWithRowbounds(
                queryExample, new RowBounds(offset, size));
        if (comments.isEmpty()) {
            return paginationDTO;
        }

        // 5. 获取相关帖子和评论信息
        // 5.1 获取所有相关帖子ID（一级评论的parentId）
        Set<Integer> postIds = comments.stream()
                .filter(c -> c.getType() == 1) // 一级评论
                .map(Comment::getParentId)
                .collect(Collectors.toSet());

        // 5.2 获取所有相关评论ID（二级评论的parentId）
        Set<Integer> commentIds = comments.stream()
                .filter(c -> c.getType() == 2) // 二级评论
                .map(Comment::getParentId)
                .collect(Collectors.toSet());

        // 5.3 批量查询相关帖子和评论
        Map<Integer, Post> postMap = new HashMap<>();
        if (!postIds.isEmpty()) {
            PostExample postExample = new PostExample();
            postExample.createCriteria().andIdIn(new ArrayList<>(postIds));
            postMapper.selectByExample(postExample).forEach(post -> postMap.put(post.getId(), post));
        }

        Map<Integer, Comment> commentMap = new HashMap<>();
        if (!commentIds.isEmpty()) {
            CommentExample commentExample = new CommentExample();
            commentExample.createCriteria().andIdIn(new ArrayList<>(commentIds));
            commentMapper.selectByExample(commentExample).forEach(comment -> commentMap.put(comment.getId(), comment));
        }

        // 6. 转换为DTO
        List<CommentDTO> commentDTOS = comments.stream().map(comment -> {
            CommentDTO commentDTO = new CommentDTO();
            BeanUtils.copyProperties(comment, commentDTO);

            // 设置关联的帖子信息
            if (comment.getType() == 1) {
                // 一级评论，直接关联帖子
                Post post = postMap.get(comment.getParentId());
                if (post != null) {
                    commentDTO.setPostId(post.getId());
                    commentDTO.setPostTitle(post.getTitle());
                }
            } else {
                // 二级评论，先找到一级评论，再关联帖子
                Comment parentComment = commentMap.get(comment.getParentId());
                if (parentComment != null && parentComment.getType() == 1) {
                    Post post = postMap.get(parentComment.getParentId());
                    if (post != null) {
                        commentDTO.setPostId(post.getId());
                        commentDTO.setPostTitle(post.getTitle());
                    }
                }
            }

            // 限制内容显示长度
            if (comment.getPlainText() != null && comment.getPlainText().length() > 100) {
                commentDTO.setShortContent(comment.getPlainText().substring(0, 100) + "...");
            } else {
                commentDTO.setShortContent(comment.getPlainText());
            }

            return commentDTO;
        }).collect(Collectors.toList());

        paginationDTO.setData(commentDTOS);
        paginationDTO.setPagination(page, totalPage);
        return paginationDTO;
    }
}
